// 构造函数 创建顶级 播放对象 Palyer
function Palyer(url, did, videoType,dataType) {
    this.ws = null; // 装载 socket
    this.decode = null; // 装载 解码器
    this.WebGLPlayer = null; // 解码 yuv
    this.socketUrl = url; // socket Url
    this.did = did || "82074201049";
    this.videoType = videoType || "1";
    this.canvasId = this.randomCoding(10); // canvasId
    this.loadingId = this.randomCoding(5);
    this.dataType = dataType || 'RTP'

    this.showLoading = true;
    this.creatDom()
    this.loading()

    this.frameList = []; // 存储解完码以后的数据
}

Palyer.prototype.creatDom = function () {
    // 动态创建dom
    // 创建 canvas 标签
    let frameDiv = document.createElement("div"); //创建一个标签
    frameDiv.setAttribute('class', 'bigBox')

    let frameCanvas = document.createElement("canvas"); //创建一个标签
    let loading = document.createElement("div"); //创建一个标签
    loading.setAttribute('class', 'loading')
    loading.setAttribute('id', this.loadingId)

    frameCanvas.setAttribute('width', 864)
    frameCanvas.setAttribute('height', 480)

    // frameCanvas.setAttribute('style', 'width:432px;height:240px')

    frameCanvas.setAttribute('class', 'videoCanvas')
    frameCanvas.setAttribute('id', this.canvasId)

    frameDiv.appendChild(frameCanvas)
    frameDiv.appendChild(loading)

    document.querySelector('.content').appendChild(frameDiv)


    this.canvas = document.querySelector('#' + this.canvasId); // canvas 标签
    this.load = document.querySelector('#' + this.loadingId)

    this.initWebGl()
    this.initWorkers()
}




Palyer.prototype.initWebGl = function () {
    if (outImgFrameType == 0) {
        this.webglPlayer = new WebGLPlayer(this.canvas, {
            preserveDrawingBuffer: false
        });
    }

}



Palyer.prototype.initWorkers = function () {
    // 初始化 worker 线程

    // time 变量用于清除缓存
    let time = new Date().getTime()

    let that = this;
    this.ws = new Worker('./js/socket.js?' + time)
    this.decode = new Worker('./js/decode.js?' + time)

    // 初始化 socket 连接 并且将 socket URL 传给 ws 线程


    this.ws.onmessage = function (msg) {
        // socket 线程 获取到消息
        let data = msg.data;
        switch (data.state) {
            case SocketStateInitErr:
                // 报错
                that.onError(data.message)
                break;
            case SocketStateInitSucc:
                console.error('WS 连接正常 通知 CODE 初始化解码器');
                // ws 链接建立正常  将信号 发送给 decode 线程  通知 初始化解码器
                that.decode.postMessage({
                    state: SocketStateInitSucc,
                    type: that.videoType,
                    dtype:that.dataType
                })
                break;
            case SocketStateSucc:
                // 数据传输 继续
                // console.error('WS 推送数据正常 传递数据给 CODE 解码')
                let o = {
                    ...data
                }
                that.decode.postMessage(o, [o.data])
                break;
            case SocketStateTimeout:
                that.showLoading = true;
                that.loading()
                console.error('WS 推送消息超过 200 毫秒')
                break;

            case SocketStateErr:
                console.error('WS 传输出错')
                break;
        }
    }

    this.decode.onmessage = function (msg) {
        // decode 线程 获取到消息
        let data = msg.data;
        switch (data.state) {
            case WasmLoaded:
                console.error('wasm初始化正常。通知 WS 打开连接');
                // wasm初始化结束  通知 ws 准备推送 初始化 数据
                that.ws.postMessage({
                    state: SocketStateInit,
                    url: that.socketUrl,
                    did: that.did,
                    dtype: that.dataType
                })
                break;

            case DecodeStateInitSucc:
                console.error('CODE 初始化解码器正常，通知 WS 推送数据');
                that.ws.postMessage({
                    state: DecodeStateInitSucc,
                })
                break;

            case DecodeStateInitErr:
                console.error('解码器初始化失败');
                break;

            case DecodeStateSucc:
                // console.error('解码器数据解码成功');
                if(that.showLoading){
                    that.showLoading = false;
                    that.loading()
                }
                that.drawingCavas(data.data, data.width, data.height)
                break;

            case DecodeStateErr:
                console.error('解码器数据解码失败');
                break;
        }
    }

}

Palyer.prototype.drawingCavas = function (data, w, h) {
    if (outImgFrameType == 0) {
        // console.log( w, h, w * h, (w / 2) * (h / 2));
        this.webglPlayer.renderFrame(data, w, h, w * h, (w / 2) * (h / 2));
        data = null;

    } else {

        let ctx = this.canvas.getContext('2d');
        let imgData = ctx.createImageData(w, h);

        for (var i = 0, j = 0; i < imgData.data.length; i += 4, j += 3) {
            //之所以这样是因为canvas只接受rgba数据，而我们只有rgb,因此最后一个直接为255即可
            imgData.data[i + 0] = data[j + 0];
            imgData.data[i + 1] = data[j + 1];
            imgData.data[i + 2] = data[j + 2];
            imgData.data[i + 3] = 255;
        }
        ctx.putImageData(imgData, 0, 0); //后边的两个参数是渲染的起始位置，这里就设为（0，0）了，表示左上角        
    }

}


Palyer.prototype.loading = function () {
    if (this.showLoading) {
        // 展示加载动画
        if (this.load.style.display == 'block') return
        this.load.style.display = 'block'
    } else {
        // 隐藏加载动画
        if (this.load.style.display == 'none') return
        this.load.style.display = 'none'
    }
}

Palyer.prototype.onError = function (err) {
    // 报错函数 后期改造成弹框
    console.log('报错通知：' + err);
}


Palyer.prototype.onClose = function () {


    // 清空 canvas
    let gl = this.canvas.getContext("webgl") || this.canvas.getContext("experimental-webgl");
    gl.clear(gl.COLOR_BUFFER_BIT)
    // 关闭视频通道
    this.ws.postMessage({
        state: SocketStateClose
    })
    // 关闭解码器
    this.decode.postMessage({
        state: DecodeStateClose
    })
}




Palyer.prototype.randomCoding = function (sum) {
    // 获取随机字母
    let result = [];
    let n = sum; //这个值可以改变的，对应的生成多少个字母，根据自己需求所改
    for (let i = 0; i < n; i++) {
        //生成一个0到25的数字
        let ranNum = Math.ceil(Math.random() * 25);
        //大写字母'A'的ASCII是65,A~Z的ASCII码就是65 + 0~25;
        //然后调用String.fromCharCode()传入ASCII值返回相应的字符并push进数组里
        result.push(String.fromCharCode(65 + ranNum));
    }
    return result.join('');
}